/*
  Copyright 2006 by Sean Luke and George Mason University
  Licensed under the Academic Free License version 3.0
  See the file "LICENSE" for more information
*/

package sim.util.media.chart;

import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.*;

// From MASON (cs.gmu.edu/~eclab/projects/mason/)
import sim.util.gui.*;

// From JFreeChart (jfreechart.org)
import org.jfree.data.xy.*;
import org.jfree.chart.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.data.general.*;

// from iText (www.lowagie.com/iText/)
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

/*  // looks like we'll have to move to these soon
    import com.itextpdf.text.*;
    import com.itextpdf.text.pdf.*;
*/

/**
   TimeSeriesChartGenerator is a ChartGenerator which displays a time-series chart using the JFreeChart library.
   The generator uses the XYSeriesCollection as its dataset, and thus holds some N XYSeriesDataset objects, each
   representing a time series displayed on the chart.  You add series to the generator with the <tt>addSeries</tt>
   method.
   
   <p>TimeSeriesChartGenerator creates attributes components in the form of TimeSeriesAttributes, which work with
   the generator to properly update the chart to reflect changes the user has made to its display.
*/

public class TimeSeriesChartGenerator extends ChartGenerator
    {
    public void removeSeries(int index)
        {
        super.removeSeries(index);
        XYSeriesCollection xysc = (XYSeriesCollection) getSeriesDataset();
        xysc.removeSeries(index);
        }
                
    public void moveSeries(int index, boolean up)
        {
        super.moveSeries(index, up);
                
        if ((index > 0 && up) || (index < getSeriesDataset().getSeriesCount() - 1 && !up))  // it's not the first or the last given the move
            {
            XYSeriesCollection xysc = (XYSeriesCollection) getSeriesDataset();
            // this requires removing everything from the dataset and resinserting, duh
            ArrayList items = new ArrayList(xysc.getSeries());
            xysc.removeAllSeries();
            
            int delta = up? -1:1;
            // now rearrange
            items.add(index + delta, items.remove(index));
            
            // rebuild the dataset
            for(int i = 0; i < items.size(); i++)
                xysc.addSeries(((XYSeries)(items.get(i))));
            }
        }

    /** Adds a series, plus a (possibly null) SeriesChangeListener which will receive a <i>single</i>
        event if/when the series is deleted from the chart by the user.  The series should have a key
        in the form of a String.  Returns the series attributes. */
    public TimeSeriesAttributes addSeries( final XYSeries series, final SeriesChangeListener stopper)
        {
        XYSeriesCollection xysc = (XYSeriesCollection) getSeriesDataset();

        int i = xysc.getSeriesCount();
        xysc.addSeries(series);
        TimeSeriesAttributes csa = new TimeSeriesAttributes(this, series, i, stopper); 
        seriesAttributes.add(csa);
        revalidate();
        return csa;
        }
        
    
    protected void buildChart()
        {
        XYSeriesCollection collection = new XYSeriesCollection();
                
        chart = ChartFactory.createXYLineChart("Untitled Chart","Untitled X Axis","Untitled Y Axis", collection,
            PlotOrientation.VERTICAL, false, true, false);
        ((XYLineAndShapeRenderer)(((XYPlot)(chart.getPlot())).getRenderer())).setDrawSeriesLineAsPath(true);

        chart.setAntiAlias(true);
        chartPanel = new ChartPanel(chart, true);                       
        chartPanel.setPreferredSize(new java.awt.Dimension(640,480));
        chartPanel.setMinimumDrawHeight(10);
        chartPanel.setMaximumDrawHeight(2000);
        chartPanel.setMinimumDrawWidth(20);
        chartPanel.setMaximumDrawWidth(2000);
        chartHolder.getViewport().setView(chartPanel);
                
        // this must come last because the chart must exist for us to set its dataset
        setSeriesDataset(collection);
        }


    JCheckBox useCullingCheckBox;
    NumberTextField maxPointsPerSeriesTextField;
    DataCuller dataCuller;
    public DataCuller getDataCuller() {return dataCuller;}
    public void setDataCuller(DataCuller dataCuller) {this.dataCuller = dataCuller;}
    
    public TimeSeriesChartGenerator()
        {
        super();
        LabelledList globalAttribList = (LabelledList) (((DisclosurePanel)getGlobalAttribute(-2)).getDisclosedComponent());
        useCullingCheckBox = new JCheckBox();
        
        globalAttribList.add(new JLabel("Cull Data"), useCullingCheckBox);
        maxPointsPerSeriesTextField = new NumberTextField(1000)
            {
            public double newValue(final double val)
                {
                int max = (int)val;
                if(val<2)
                    return (int)getValue();
                dataCuller = new MinGapDataCuller(max);
                return max;
                }
            };
        useCullingCheckBox.setSelected(true);
        globalAttribList.add(new JLabel("... Over"),maxPointsPerSeriesTextField);
        maxPointsPerSeriesTextField.setToolTipText("The maximum number of data points in a series before data culling gets triggered.");

        dataCuller = new MinGapDataCuller((int)maxPointsPerSeriesTextField.getValue());

        
        useCullingCheckBox.addActionListener(new ActionListener()
            {
            public void actionPerformed(ActionEvent event)
                {
                if(useCullingCheckBox.isSelected())
                    {
                    maxPointsPerSeriesTextField.setEnabled(true);
                    int maxPoints = (int)maxPointsPerSeriesTextField.getValue();
                    dataCuller = new MinGapDataCuller(maxPoints);
                    }
                else
                    {
                    maxPointsPerSeriesTextField.setEnabled(false);
                    dataCuller = null;
                    }
                }
            }); 

        }
    }
